package coalition.formation.coalitions;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import coalition.formation.combinations.Combination;
import coalition.formation.combinations.SuperSet;
import coalition.formation.externality.Externality;
import coalition.formation.partitions.Partition;
import coalition.formation.partitions.PartitionDecorator;
import coalition.formation.utils.Util;




public class NoTreat {
	
	Externality externality;
	int numElements;

	public NoTreat(Externality externality){
		this.externality = externality;
		this.numElements = externality.getSize();
	}
	
	public List<int[]> getNoTreatPartitions(){
		Partition testPartition = new Partition(numElements);
		ArrayList<int[]> partitions = testPartition.getPartitions();
		return getNoTreatPartitions(partitions);
	}
	
	public List<int[]> getNoTreatPartitions(List<int[]> partitions){
		List<int[]> result = new ArrayList<int[]>();
		
		List<int[]> combinations = SuperSet.getSuperSetMinusEmptySet(numElements);
			
		for(int[] partition : partitions){
			System.out.println("starting partition:" + coalition.formation.utils.Util.printIntArray(partition));
			float[] thisExternalities = externality.getExternalities(partition);
			System.out.println("\texternalities:" + coalition.formation.utils.Util.printFloatArray(thisExternalities)+ "\n");
			boolean isCore = true;
			for(int[] coalitionIndicatorArray: combinations){
					
				int[] coalition = Core.getCoalitionFromCoalitionIndicatorArray(coalitionIndicatorArray);
				
				if(coalition.length == numElements){
					//don't test everybody defecting to the same group
					//because that's covered by the core coalition test
					continue;
				}
				
				System.out.println("\tcoalition indicator:" + Util.printIntArray(coalitionIndicatorArray));
				System.out.println("\tcoalition list:" + Util.printIntArray(coalition));
				
				int[] coalitionComplement = Core.getCoalitionComplement(coalition, partition.length);
				int[] coalitionComplementIndicatorArray = 
					Core.getCoalitionComplementIndicatorArray(coalition, partition.length);
				
				int[] otherPartition = getPartitionAfterDefection(partition, coalition);
				System.out.println("\tresulting partition:" + Util.printIntArray(otherPartition) );
				
				float[] otherExternalities = externality.getExternalities(otherPartition);
				
				boolean isGreaterThan = Core.floatArrayGreaterThan(otherExternalities, thisExternalities, coalition);
				String cmpSymbol = isGreaterThan ? " > " : " !> ";
				System.out.println("\tresulting externalities:" + 
						Util.printFloatArray(otherExternalities, coalitionIndicatorArray) + 
						cmpSymbol + 
						Util.printFloatArray(thisExternalities, coalitionIndicatorArray) );
				
				if(isGreaterThan){
					System.out.println("\tadvantageous defection");
					
					int[] threatPartition = getThreatPartition(partition, coalition);
					System.out.println("\tthreatening partition:" + Util.printIntArray(threatPartition) );
					
					float[] threatExternalities = externality.getExternalities(threatPartition);
					
					boolean threateningAgentsWeaklyBetterOff = Core.floatArrayWeaklyGreaterThan(threatExternalities, otherExternalities, coalitionComplement);
					cmpSymbol = threateningAgentsWeaklyBetterOff ? " >= " : " !>= ";
					System.out.println("\tthreateningAgentsWeaklyBetterOff?");
					System.out.println("\tthreatening agents threatened externalities:" + 
							Util.printFloatArray(threatExternalities, coalitionComplementIndicatorArray) + 
							"\n\t" + cmpSymbol + "\n\t" +
							Util.printFloatArray(otherExternalities, coalitionComplementIndicatorArray) 
							+ ":threatening agents non-threat externalities "		
					);
					
					boolean defectingAgentsWorseOff = !Core.floatArrayWeaklyGreaterThan(threatExternalities, otherExternalities, coalition);
					cmpSymbol = defectingAgentsWorseOff ? " !>= " : " >= ";
					System.out.println("\tdefectingAgentsWorseOff?");
					System.out.println("\tdefecting agents threatened externalities:" + 
							Util.printFloatArray(threatExternalities, coalitionIndicatorArray) + 
							"\n\t" + cmpSymbol + "\n\t" +
							Util.printFloatArray(otherExternalities, coalitionIndicatorArray) 
							+ ":defecting agents attempted externalities "
					);					
					
					System.out.println("\tthreateningAgentsWeaklyBetterOff: " + threateningAgentsWeaklyBetterOff);
					System.out.println("\tdefectingAgentsWorseOff: " + defectingAgentsWorseOff);
					if(threateningAgentsWeaklyBetterOff && defectingAgentsWorseOff){
						System.out.println("\tno treat was determinative here.");
					} else {
						isCore = false;
						System.out.println("\tno treat was not determinative here.");
						System.out.println("\tso we have a stability violation");
						
					}
					
				}
				System.out.println("");
			}		
			if(isCore)
				result.add(partition);					
		}
		
		return result;
	}

	static int[] getPartitionAfterDefection(int[] partition, int[] defectingAgentIndices){
		int[] newPartition = Arrays.copyOf(partition, partition.length);
		for(int i : defectingAgentIndices){
			//use an index one greater than anything present in
			//a normalized partition; this new index will represent
			//the splitting group
			newPartition[i] = partition.length;
		}	
		int[] normalizedPartition = PartitionDecorator.reduceIndices(newPartition);
		return normalizedPartition;
	}	
	
	static int[] getThreatPartition(int[] partition, int[] defectingAgentIndices){
		int[] newPartition = new int[partition.length];
		for(int i : defectingAgentIndices){
			//use an index one greater than anything present in
			//a normalized partition; this new index will represent
			//the splitting group
			newPartition[i] = partition.length;
		}	
		int[] normalizedPartition = PartitionDecorator.reduceIndices(newPartition);
		return normalizedPartition;
	}	
	
}